/**
 * @filename Vector.h
 * @brief An Example Vector ADT 
 * @author Sun Zehui <sunzehui18@outlook.com>
 * @version 1.0.0
 * @date 2021-10-18
 */
#include<iostream>
#include<algorithm>
using namespace std;

/**
 * @brief 定义闲置的容量大小，为方便测试改为全局定义变量
 */
extern int SPARE_CAPACITY;

class VectorTypeError{
public:
    VectorTypeError(){}
    ~VectorTypeError(){}
    void diagnostic(){
        cerr << "push item raise type error!";
    }
};


class VectorIndexError { 
public: 
    VectorIndexError(int v) : m_badValue(v) { } 
    ~VectorIndexError() { } 
    void diagnostic() { 
        cerr << "index " << m_badValue << "out of range!"; } 
private: 
    int m_badValue; 
};

/**
 * @brief Vector Class 
 *
 * @tparam Object A generic type, can be arbitrary variable type
 */
template <typename Object>
class Vector{
public:
    
    Vector(int initSize = 0): theSize(initSize), theCapacity(initSize+SPARE_CAPACITY)
    {
        objects = new Object[theCapacity];
    }

    /**
     * @brief Vector copy constructor  
     *
     * @param rhs.theSize, rhs.theCapacity for list initialization
     */
    Vector(const Vector & rhs): theSize(rhs.theSize), theCapacity(rhs.theCapacity), objects(nullptr){
        objects = new Object[ theCapacity ];
        for (int k=0; k<theSize; ++k)
	{
            objects[k] = rhs.objects[k];
        }
    }

    /**
     * @brief operator= overload operator=.
     *
     * @param rhs Vector& 传递一个左值常量引用，由于没有赋予
     * 移动语义，所以进行了一波深拷贝，再进行交换，返回*this引用
     *
     * @return return Vector&
     */
    Vector& operator=(const Vector& rhs)
    {
        Vector copy = rhs;
        swap(*this, copy);
        return *this;        
    }

    ~Vector(){delete [] objects;}

    /**
     * @brief Vector MoveCopyConstructor, 做完赋值之后直接空悬rvalue
     *
     * @param rv_rhs for list initialization
     */
    Vector(Vector && rhs): theSize(rhs.theSize), theCapacity(rhs.theCapacity), objects(rhs.objects)
    {
        rhs.objects = nullptr;
        rhs.theSize = 0;
        rhs.theCapacity = 0;
    }
    
    /**
     * @brief operator= overload function, accept right value
     * 这里直接使用swap函数，是因为接受右值可以不用管rvalue了，因为他们马上消亡
     * 所以使用swap无可厚非，但是多叠了一层栈结构，可以改为直接指针赋值然后空悬原右值
     *
     * @param rhs right value
     *
     * @return 
     */
    Vector& operator= (Vector&& rhs){
        swap(theSize, rhs.theSize);
        swap(theCapacity, rhs.theCapacity);
        swap(objects, rhs.objects);
        
        return *this;
    }

    /**
     * @brief resize 改变大小，除非超出容量大小都则就改变一个theSize即可
     *
     * @param newSize int
     */
    void resize(int newSize)
    {
        if(newSize > theCapacity)
            reserve(newSize*2);
        theSize = newSize;
    }

    /**
     * @brief reserve 预留容量空间，并且将原本的数据移动赋值过来
     *
     * @param newCapacity new capacity of Vector
     */
    void reserve(int newCapacity)
    {
        if(newCapacity<theSize) //只有当容量大于size的时候才会预留空间
            return;
        
        Object *newArray = new Object[newCapacity];
        for(int k=0; k<theSize; ++k){
            newArray[k] = move(objects[k]);//这里默认了new出来的type object ADT默认有移动赋值后空悬，否则必报段错误！
        }

        theCapacity = newCapacity;
        swap(objects, newArray);
        delete [] newArray;
    }

    /**
     * @brief operator[] overload 可以被改变，增加了处理越界情况
     *
     * @param index
     *
     * @return Object& lvalue
     */
    Object& operator[](int index){
        try
        {
            if (index < 0 || index >= size()) { throw VectorIndexError(index); }
            return objects[index];
        }catch (VectorIndexError& e)
            { //捕捉这个抛出的异常执行，对每一次抛出传递已经无法回到上一层//执行catch和之后的语句
                e.diagnostic();
                delete[] objects;
            }
    }

    /**
     * @brief operator[] overload 不可以改变，增加了处理越界情况
     *
     * @param index 
     *
     * @return Object& const
     */
    const Object& operator[](int index) const
    {   
        try
        {
            if (index < 0 || index >= size()) { throw VectorIndexError(index); }
            return objects[index];
        }catch (VectorIndexError& e)
            { //捕捉这个抛出的异常执行，对每一次抛出传递已经无法回到上一层//执行catch和之后的语句
                e.diagnostic();
                delete[] objects;
            }
    }

    bool empty() const
    {
        return size() == 0;
    }
    int size() const
    {   
        return theSize;
    }
    int capacity() const
    {
        return theCapacity;
    }


    /**
     * @brief push_back 推入一个const Object&，超出size时改变capacity大小
     *
     * @param x const Object&
     */
    void push_back(const Object& x)
    {
        if(theSize == theCapacity)
            reserve(2*theCapacity + 1);
        objects[theSize++] = x;
    }

    /**
     * @brief push_back 推入一个右值，同上
     *
     * @param x rvalue
     */
    void push_back( Object&& x )
    {
           
        if(theSize == theCapacity)
            reserve(2*theCapacity + 1);
        objects[ theSize++ ] = move(x);
    }
    
    /**
     * @brief pop_back pop出一个元素，简单将theSize--
     */
    void pop_back(){
        --theSize;
    }

    const Object& back() const
    {
        return objects[theSize-1];
    }

    /**
     * @brief 定义iterator变量类型
     */
    typedef Object* iterator;
    typedef const Object* const_iterator;

    /**
     * @brief begin 返回首位置地址赋予iterator指针，iterator++意味着
     * 指针按照size_t(variable)向前移动，即成为下一个元素的指针
     *
     * @return iterator指针类型
     */
    iterator begin()
    {
        return &objects[0];
    }

    /**
     * @brief begin 返回Const_iterator，不能改变指针所指对象
     * 不同于const iterator不能改变指针本身，但能改变指针所指对象
     *
     * @return const_iterator
     */
    const_iterator begin() const
    {
        return &objects[0];
    }

    iterator end()
    {
        return &objects[size()];
    }
    const_iterator end() const
    {
        return &objects[size()];
    }

    

private:
    int theSize;
    int theCapacity;
    Object* objects;

};
